//      filesystem.c
//      
//      Copyright 2012 Mukesh <mukesh_fun2010@yahoo.in>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.


#include <gmodule.h>
#include "filesystem.h"

void gesbian_plugin_init ( GesbianPlugin * g )
{
	in ;
	g_debug ( "Filesystem plugin activated." ) ;
	
	gtk_tree_sortable_set_default_sort_func ( 	g -> store,
												filesystem_sort_func,
												g,
												NULL ) ;
	
	filesystem_ui_init ( g ) ;
	
	gesbian_plugin_uri_open ( g, NULL ) ;
	out ;
}

void gesbian_plugin_uri_open ( GesbianPlugin * g, gchar * uri )
{
	in ;
	
	if ( uri != NULL && ! g_file_test ( uri, G_FILE_TEST_EXISTS ))
	{
		g_warning ( "Cannot open %s! No such file or directory !", uri ) ;
		return ;
	}
	
	g -> event_id = g_random_int () ;
	gint event_id = g -> event_id ;
	
	gtk_spinner_start ( g -> spinner ) ;
	gtk_widget_show ( g -> progressbar ) ;
	gtk_widget_show ( g -> spinner ) ;
	
	GtkListStore * store = g -> store ;
	if ( store == NULL )
	{
		g_critical ( "store passed as null !" ) ;
		
		out ;
		return ;
	}
	
	
	GError * error = NULL ;
	GDir * dir = NULL ;
	
	if ( uri != NULL )
		dir = g_dir_open ( uri, 0, & error ) ;
	else
	{
		uri = g_get_home_dir () ;
		dir = g_dir_open ( uri, 0, & error ) ;
	}
	
	GList * have_we_been_here_before_question_mark = g_list_find ( g -> history, uri ) ;
	if ( have_we_been_here_before_question_mark == NULL )
	{
		g -> history = g_list_append ( g -> history, g_strdup ( uri )) ;
		g -> history_marker = g_list_length ( g -> history ) - 1 ;
	}
	else
		g -> history_marker = g_list_position ( g -> history, have_we_been_here_before_question_mark ) ;
	
	if ( dir == NULL )
	{
		g_critical ( "%s: Cannot open folder: %s", __func__, error -> message ) ;
		out ;
		
		return ;
	}

	gchar * name = g_dir_read_name ( dir ) ;
	gtk_list_store_clear ( store ) ;
	
	gint counter = 0, items = 0, current = 0 ;
	gtk_statusbar_push ( g -> statusbar, 0, "Opening folder ..." ) ;
	
	gtk_widget_set_sensitive ( g -> stop, 1 ) ;
	gtk_entry_set_text ( g -> locationbar, uri ) ;
	
	filesystem_sidebar_clear ( g ) ;
	
	while ( name != NULL )
	{
		if ( name [0] != '.' )
			items ++ ;
		
		name = g_dir_read_name ( dir ) ;
	}
	
	g_dir_rewind ( dir ) ;
	name = g_dir_read_name ( dir ) ;
	
	while ( name != NULL )
	{
		if ( event_id != g -> event_id )
			break ;
		
		if ( name [0] == '.' )
		{
			name = g_dir_read_name ( dir ) ;
			continue ;
		}
		
		GtkTreeIter iter ;
		gtk_list_store_append ( store, & iter ) ;
		
		gchar * filename = g_build_filename ( uri, name, NULL ) ;
		GdkPixbuf * p = filesystem_get_icon ( filename ) ;
		
		gtk_list_store_set ( store, & iter, 0, name, 1, filename, 2, p, -1 ) ;
		
		g_object_unref ( p ) ;
		g_free ( filename ) ;
		
		counter ++ ;
		current ++ ;
		
		if ( counter > 10 )
		{
			gtk_progress_bar_set_fraction ( g -> progressbar, ( gfloat ) current / ( gfloat ) items ) ;

			while ( gtk_events_pending ())
				gtk_main_iteration_do ( FALSE ) ;
			
			counter = 0 ;
		}
		
		name = g_dir_read_name ( dir ) ;
	}
	
	gtk_spinner_stop ( g -> spinner ) ;
	gtk_widget_set_sensitive ( g -> stop, 0 ) ;
	
	gtk_widget_hide ( g -> progressbar ) ;
	gtk_widget_hide ( g -> spinner ) ;
	
	gtk_statusbar_pop ( g -> statusbar, 0 ) ;
	g_dir_close ( dir ) ;
	
	out ;
	return ;
}

gchar * filesystem_get_mime_type ( gchar * filename )
{
	//in ;
	
	gchar * t = tmpnam ( NULL ) ;
	gchar * command = g_strdup_printf ( "file --mime-type -b \"%s\" > %s", filename, t ) ;
	
	system ( command ) ;
	g_free ( command ) ;
	
	GError * error = NULL ;
	gchar * text = NULL ;
	
	if ( ! g_file_get_contents ( t, & text, NULL, & error ))
	{
		g_critical ( "%s: %s", __func__, error -> message ) ;
		
	//	out ;
		return ;
	}
	
	remove ( t ) ;
	
//	out ;
	return text ;
}

GdkPixbuf * filesystem_get_icon ( gchar * filename )
{
//	in ;
	
	if ( g_file_test ( filename, G_FILE_TEST_IS_DIR ))
	{
		GdkPixbuf * p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												"gtk-directory",
												32,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												NULL ) ;
		return p ;
	}		
	
	gchar * mime_type = filesystem_get_mime_type ( filename ) ;
	gchar ** vector = g_strsplit ( mime_type, "/", 2 ) ;
	
	gchar 	* mime = NULL,
			* type = NULL ;
	
	if ( vector [0] )
	{
		mime = vector [0] ;
	
		if ( vector [1] )
			type = vector [1] ;
		
	}
	
	GError * error = NULL ;
	GdkPixbuf * p = NULL ;
	
	if ( type != NULL )
		p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												type,
												32,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												& error ) ;
	
	if ( p == NULL && mime!= NULL )
	{
//		g_warning ( "%s: %s", __func__, error -> message ) ;
		error = NULL ;
		
		p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												mime,
												32,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												& error ) ;
	}
		

	if ( p == NULL )
	{
//		g_warning ( "%s: %s", __func__, error -> message ) ;
		error = NULL ;
		
		p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												"gtk-file",
												32,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												& error ) ;
	}
	
	g_strfreev ( vector ) ;
	g_free ( mime_type ) ;
	
//	out ;
	return p ;
}

gint filesystem_sort_func ( GtkTreeModel * model, GtkTreeIter * iter1,
							 GtkTreeIter * iter2, GesbianPlugin * g )
{
	gchar 	* name1 = NULL, * name2 = NULL,
			* full_name1 = NULL, * full_name2 = NULL ;
	
	gtk_tree_model_get ( model, iter1, 0, & name1, 1, & full_name1, -1 ) ;
	gtk_tree_model_get ( model, iter2, 0, & name2, 1, & full_name2, -1 ) ;
	
	gint result = 0 ;
	gboolean 	is_dir1 = g_file_test ( full_name1, G_FILE_TEST_IS_DIR ),
				is_dir2 = g_file_test ( full_name2, G_FILE_TEST_IS_DIR ) ;
	
	gchar 	* name3 = g_ascii_strdown ( name1, -1 ),
			* name4 = g_ascii_strdown ( name2, -1 ) ;
	
	if ( is_dir1 && ! is_dir2 )
		result = -1 ;
	
	else if ( ! is_dir1 && is_dir2 )
		result = 1 ;
	
	else
		result = strcmp ( name3, name4 ) ;
	/*
	{
		gint 	i = 0,
				len1 = strlen ( name1 ),
				len2 = strlen ( name2 ) ;
		
		while ( name1 [i] == name2 [i] )
			if ( i < len1 && i < len2 )
				i ++ ;
		
		result = name1 [i] - name2 [i] ;
	}
	*/
	
	g_free ( full_name1 ) ;
	g_free ( full_name2 ) ;

	g_free ( name1 ) ;
	g_free ( name2 ) ;
	
	g_free ( name3 ) ;
	g_free ( name4 ) ;
	
	//g_debug ( "%s and %s got result %d", name1, name2, result ) ;
	return result ;
}

void filesystem_item_activated ( GtkIconView * iconview,
								GtkTreePath * path,
								GesbianPlugin * g )
{
	GtkTreeIter iter ;
	gtk_tree_model_get_iter ( g -> store, & iter, path ) ;
	
	gchar * filename = NULL ;
	gtk_tree_model_get ( g -> store, & iter, 1, & filename, -1 ) ;
	
	if ( g_file_test ( filename, G_FILE_TEST_IS_DIR ))
	{
		gesbian_plugin_uri_open ( g, filename ) ;
		g_free ( filename ) ;
		
		return ;
	}
}

void filesystem_ui_init ( GesbianPlugin * g )
{
	//gtk_widget_set_sensitive ( g -> addressbar, 0 ) ;
	//gtk_widget_set_sensitive ( g -> addressbar_button, 0 ) ;
	
	gtk_widget_hide ( g -> addressbar ) ;
	gtk_widget_hide ( g -> addressbar_button ) ;
	
	gtk_widget_set_sensitive ( g -> locationbar, 1 ) ;
	gtk_widget_set_sensitive ( g -> locationbar_go, 1 ) ;
	gtk_label_set_text ( g -> title, "Filesystem" ) ;
	
	gtk_tree_sortable_set_sort_column_id ( g -> store, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING ) ;
	g_signal_connect ( g -> iconview, "item-activated", filesystem_item_activated, g ) ;

	g -> history = NULL ;
	g -> history_marker = 0 ;

	g -> event_id = 0 ;

	g_signal_connect_swapped ( g -> back, "clicked", filesystem_go_back, g ) ;
	g_signal_connect_swapped ( g -> next, "clicked", filesystem_go_forward, g ) ;
	g_signal_connect_swapped ( g -> home, "clicked", filesystem_go_home, g ) ;
	g_signal_connect_swapped ( g -> stop, "clicked", filesystem_stop, g ) ;
	g_signal_connect_swapped ( g -> up, "clicked", filesystem_go_up, g ) ;

	g_signal_connect_swapped ( g -> locationbar_go, "clicked", filesystem_go, g ) ;
	g_signal_connect_swapped ( g -> locationbar, "activate", filesystem_go, g ) ;
	
	g_signal_connect_swapped ( g -> iconview, "selection-changed", filesystem_sidebar_set_info, g ) ;
	
	g_signal_connect_after ( g -> window, "key-press-event", filesystem_keyboard_shortcuts, g ) ;
	gtk_widget_grab_focus ( g -> iconview ) ;
}	

void filesystem_go_back ( GesbianPlugin * g )
{
	if ( g -> history_marker > 0 )
		gesbian_plugin_uri_open ( g, g_list_nth_data ( g -> history, g -> history_marker - 1 )) ;
}

void filesystem_go_forward ( GesbianPlugin * g )
{	
	if ( g_list_length ( g -> history ) > g -> history_marker + 1 )
		gesbian_plugin_uri_open ( g, g_list_nth_data ( g -> history, g -> history_marker + 1 )) ;
}

void filesystem_go_home ( GesbianPlugin * g )
{
	gesbian_plugin_uri_open ( g, g_get_home_dir ()) ;
}

void filesystem_stop ( GesbianPlugin * g )
{
	g -> event_id = g_random_int () ;
}

void filesystem_go ( GesbianPlugin * g )
{
	gesbian_plugin_uri_open ( g, gtk_entry_get_text ( g -> locationbar )) ;
}

void filesystem_go_up ( GesbianPlugin * g )
{
	gchar * parent = g_path_get_dirname ( gtk_entry_get_text ( g -> locationbar )) ;
	gesbian_plugin_uri_open ( g, parent ) ;

	g_free ( parent ) ;
}

gboolean filesystem_keyboard_shortcuts ( GtkWidget * widget, GdkEventKey * event, GesbianPlugin * g )
{
	switch ( event -> keyval )
	{
		case GDK_Left:
			if ( event -> state == GDK_MOD1_MASK )
				filesystem_go_back ( g ) ;
			break ;
		case GDK_Right:
			if ( event -> state == GDK_MOD1_MASK )
				filesystem_go_forward ( g ) ;
			break ;
		case GDK_Up:
			if ( event -> state == GDK_MOD1_MASK )
				filesystem_go_up ( g ) ;
			break ;
		case GDK_w:
		case GDK_W:
		case GDK_q:
		case GDK_Q:
			if ( event -> state == GDK_CONTROL_MASK )
				exit (0) ;
			break ;
		case GDK_Escape:
			filesystem_stop ( g ) ;
			break ;
		default:
			gtk_true () ;
	}
}

gchar * filesystem_get_selected_item ( GesbianPlugin * g )
{
	GList * list = gtk_icon_view_get_selected_items ( g -> iconview ) ;
	GtkTreeIter iter ;
	
	gtk_tree_model_get_iter ( g -> store, & iter, g_list_nth_data ( list, 0 )) ;
	gchar * filename = NULL ;
	
	gtk_tree_model_get ( g -> store, & iter, 1, & filename, -1 ) ;
	
	g_list_foreach ( list, gtk_tree_path_free, NULL ) ;
	g_list_free ( list ) ;
	
	return filename ;
}

GdkPixbuf * filesystem_get_thumbnail ( gchar * filename )
{
//	in ;
	
	if ( g_file_test ( filename, G_FILE_TEST_IS_DIR ))
	{
		GdkPixbuf * p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												"gtk-directory",
												128,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												NULL ) ;
		return p ;
	}		
	
	gchar * mime_type = filesystem_get_mime_type ( filename ) ;
	gchar ** vector = g_strsplit ( mime_type, "/", 2 ) ;
	
	gchar 	* mime = NULL,
			* type = NULL ;
	
	if ( vector [0] )
	{
		mime = vector [0] ;
	
		if ( vector [1] )
			type = vector [1] ;
		
	}
	
	GError * error = NULL ;
	GdkPixbuf * p = NULL ;
	
	if ( g_strrstr ( mime_type, "image" ) != NULL )
		p = gdk_pixbuf_new_from_file_at_scale ( filename, 128, 128, 1, & error ) ;
	
	else if ( type != NULL )
		p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												type,
												128,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												& error ) ;
	
	if ( p == NULL && mime!= NULL )
	{
//		g_warning ( "%s: %s", __func__, error -> message ) ;
		error = NULL ;
		
		p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												mime,
												128,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												& error ) ;
	}
		

	if ( p == NULL )
	{
//		g_warning ( "%s: %s", __func__, error -> message ) ;
		error = NULL ;
		
		p = gtk_icon_theme_load_icon (	gtk_icon_theme_get_default (),
												"gtk-file",
												128,
												GTK_ICON_LOOKUP_USE_BUILTIN |
												GTK_ICON_LOOKUP_GENERIC_FALLBACK,
												& error ) ;
	}
	
	g_strfreev ( vector ) ;
	g_free ( mime_type ) ;
	
//	out ;
	return p ;
}

gchar * filesystem_get_mime_info ( gchar * filename )
{
	//in ;
	
	gchar * t = tmpnam ( NULL ) ;
	gchar * command = g_strdup_printf ( "file -b \"%s\" > %s", filename, t ) ;
	
	system ( command ) ;
	g_free ( command ) ;
	
	GError * error = NULL ;
	gchar * text = NULL ;
	
	if ( ! g_file_get_contents ( t, & text, NULL, & error ))
	{
		g_critical ( "%s: %s", __func__, error -> message ) ;
		
	//	out ;
		return ;
	}
	
	remove ( t ) ;
	
//	out ;
	return text ;
}


void filesystem_sidebar_set_info ( GesbianPlugin * g )
{
	in ;
	
	// bit clever
	if ( GTK_WIDGET_VISIBLE ( g -> spinner ))
	{
		out ;
		return ;
	}
	
	gchar * filename = filesystem_get_selected_item ( g ) ;
	GdkPixbuf * p = filesystem_get_thumbnail ( filename ) ;

	gchar * info = filesystem_get_mime_info ( filename ) ;
	gchar * name = g_path_get_basename ( filename ) ;
	
	gchar * s = g_markup_printf_escaped ( 	"<span><b><big>%s</big></b>\n\n"
											"%s"
											"</span>",
											name,
											info ) ;
	
	gtk_label_set_markup ( g -> preview_label, s ) ;
	
	g_free ( s ) ;
	g_free ( filename ) ;
	g_free ( info ) ;
	g_free ( name ) ;
	
	gtk_image_set_from_pixbuf ( g -> preview_image, p ) ;
	g_object_unref ( p ) ;
	
	out ;
}

void filesystem_sidebar_clear ( GesbianPlugin * g )
{
	gtk_image_set_from_pixbuf ( g -> preview_image, NULL ) ;
	gtk_label_set_text ( g -> preview_label, NULL ) ;
}
